package com.itdct.onflow.core.mp

import com.baomidou.mybatisplus.annotation.DbType
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils
import com.baomidou.mybatisplus.core.toolkit.PluginUtils
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor
import com.baomidou.mybatisplus.extension.plugins.pagination.Page
import com.baomidou.mybatisplus.extension.plugins.pagination.dialects.IDialect
import com.itdct.onflow.core.context.BaseContext
import com.itdct.onflow.core.context.ContextHolder.Companion.getContext
import com.itdct.onflow.core.dto.BaseLoginDTO
import org.apache.ibatis.executor.Executor
import org.apache.ibatis.mapping.BoundSql
import org.apache.ibatis.mapping.MappedStatement
import org.apache.ibatis.session.ResultHandler
import org.apache.ibatis.session.RowBounds
import java.sql.SQLException

/**
 * @author DCT
 * @version 1.0
 * @date 2023/11/10 14:53:24
 * @description
 */
class ContextPaginationInnerInterceptor : PaginationInnerInterceptor {
    constructor(dbType: DbType?) : super(dbType)

    constructor(dialect: IDialect?) : super(dialect)

    @Throws(SQLException::class)
    override fun willDoQuery(executor: Executor, ms: MappedStatement?, parameter: Any?, rowBounds: RowBounds?, resultHandler: ResultHandler<*>?, boundSql: BoundSql): Boolean {
        // INFO: DCT: 2023/12/5 获取到当前线程的上下文对象
        val context: BaseContext<Any, BaseLoginDTO<Any>>? = getContext<Any, BaseLoginDTO<Any>>()
        if (context == null) {
            return true
        }

        // INFO: DCT: 2023/12/5 不启动分页直接跳过
        val startPage = context.startPage
        if (!startPage) {
            return true
        }

        // INFO: DCT: 2023/12/5 这个page就是MP的分页Page 
        val page: Page<*>? = context.page
        if (page == null) {
            return true
        }

        val size = page.size
        if (size <= 0) {
            page.size = 10
        }

        // INFO: DCT: 2023/12/5 以下为原来的MP分页插件代码 
        val countSql: BoundSql?
        var countMs = buildCountMappedStatement(ms, page.countId())
        if (countMs != null) {
            countSql = countMs.getBoundSql(parameter)
        } else {
            countMs = buildAutoCountMappedStatement(ms)
            val countSqlStr = autoCountSql(page, boundSql.getSql())
            val mpBoundSql = PluginUtils.mpBoundSql(boundSql)
            countSql = BoundSql(countMs.getConfiguration(), countSqlStr, mpBoundSql.parameterMappings(), parameter)
            PluginUtils.setAdditionalParameter(countSql, mpBoundSql.additionalParameters())
        }

        val cacheKey = executor.createCacheKey(countMs, parameter, rowBounds, countSql)
        val result = executor.query<Any?>(countMs, parameter, rowBounds, resultHandler, cacheKey, countSql)
        var total: Long = 0
        if (CollectionUtils.isNotEmpty(result)) {
            // 个别数据库 count 没数据不会返回 0
            val o = result!!.get(0)
            if (o != null) {
                total = o.toString().toLong()
            }
        }

        page.setTotal(total)
        var totalPage = total / page.getSize()
        if (total % page.getSize() != 0L) {
            totalPage++
        }
        page.setPages(totalPage)

        return continuePage(page)
    }

    @Throws(SQLException::class)
    override fun beforeQuery(executor: Executor?, ms: MappedStatement, parameter: Any?, rowBounds: RowBounds?, resultHandler: ResultHandler<*>?, boundSql: BoundSql) {
        val context: BaseContext<Any, BaseLoginDTO<Any>>? = getContext<Any, BaseLoginDTO<Any>>()
        if (context == null) {
            return
        }

        val startPage: Boolean = context.startPage
        if (!startPage) {
            return
        }

        // INFO: DCT: 2023/12/5 这个page就是MP的分页Page 
        val page: Page<*>? = context.page
        if (page == null) {
            return
        }

        val size = page.getSize()
        if (size < 0) {
            return
        }

        // 处理 orderBy 拼接
        var addOrdered = false
        var buildSql = boundSql.getSql()
        val orders = page.orders()
        if (CollectionUtils.isNotEmpty(orders)) {
            addOrdered = true
            buildSql = this.concatOrderBy(buildSql, orders)
        }

        // size 小于 0 且不限制返回值则不构造分页sql
        val _limit = if (page.maxLimit() != null) page.maxLimit() else maxLimit
        if (page.getSize() < 0 && null == _limit) {
            if (addOrdered) {
                PluginUtils.mpBoundSql(boundSql).sql(buildSql)
            }
            return
        }

        handlerLimit(page, _limit)
        val dialect = findIDialect(executor)

        val configuration = ms.getConfiguration()
        val model = dialect.buildPaginationSql(buildSql, page.offset(), page.getSize())
        val mpBoundSql = PluginUtils.mpBoundSql(boundSql)

        val mappings = mpBoundSql.parameterMappings()
        val additionalParameter = mpBoundSql.additionalParameters()
        model.consumers(mappings, configuration, additionalParameter)
        mpBoundSql.sql(model.getDialectSql())
        mpBoundSql.parameterMappings(mappings)

        // INFO: DCT: 2023/12/5 利用完后置为false 
        context.startPage = false
    }
}
